Bug 4736

Bug Description:

This is a deadlock.
This is a Java and native code level mixed deadlock bug. Native method java.lang.Class#forName0 in thread "Compiling and instantiation 2" and native method java.lang.Class#getDeclaredFields0 in thread "Compiling and instantiation 3" are acquiring the same lock. And both threads are acquiring the same lock on HashMap instance.
The following is an example of deadlocked thread dump:

"Compiling and instantiation 3": waiting to lock monitor 0x000000000cc5b3a8 (object 0x00000007d6ce9040,
a groovy.lang.GroovyClassLoader$InnerLoader), which is held by "Compiling and instantiation 2"
"Compiling and instantiation 2": waiting to lock monitor 0x000000000cc5bc98 (object 0x00000007d7da8070,
a java.util.HashMap),which is held by "Compiling and instantiation 3"

Java stack information for the threads listed above:
===================================================
"Compiling and instantiation 3":
at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Class.java:2387) at java.lang.Class.getDeclaredFields(Class.java:1796) at org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(Java5.java:313) at org.codehaus.groovy.ast.ClassNode.lazyClassInit(ClassNode.java:263) - locked <0x00000007d6fe9090> (a java.lang.Object) at org.codehaus.groovy.ast.ClassNode.getInterfaces(ClassNode.java:341) at org.codehaus.groovy.ast.ClassNode.declaresInterface(ClassNode.java:929) at org.codehaus.groovy.ast.ClassNode.implementsInterface(ClassNode.java:909) at org.codehaus.groovy.classgen.AsmClassGenerator.doConvertAndCast(AsmClassGenerator.java:3842) at org.codehaus.groovy.classgen.AsmClassGenerator.doConvertAndCast(AsmClassGenerator.java:3837) at org.codehaus.groovy.classgen.AsmClassGenerator.storeThisInstanceField(AsmClassGenerator.java:2840) at org.codehaus.groovy.classgen.AsmClassGenerator.visitFieldExpression(AsmClassGenerator.java:2766) at org.codehaus.groovy.ast.expr.FieldExpression.visit(FieldExpression.java:38) at org.codehaus.groovy.classgen.AsmClassGenerator.evaluateEqual(AsmClassGenerator.java:4050) at org.codehaus.groovy.classgen.AsmClassGenerator.visitBinaryExpression(AsmClassGenerator.java:1485) at org.codehaus.groovy.ast.expr.BinaryExpression.visit(BinaryExpression.java:49) at org.codehaus.groovy.classgen.AsmClassGenerator.visitAndAutoboxBoolean(AsmClassGenerator.java:4122) at org.codehaus.groovy.classgen.AsmClassGenerator.visitExpressionStatement(AsmClassGenerator.java:1466) at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40) at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:35) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:165) at org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(AsmClassGenerator.java:738) at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:101) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:112) at org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(AsmClassGenerator.java:626) at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:601) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructor(ClassCodeVisitorSupport.java:119) at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructor(AsmClassGenerator.java:688) at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1035) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:50) at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:276) at org.codehaus.groovy.control.CompilationUnit$12.call(CompilationUnit.java:748) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:942) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:519) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:497) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:474) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:306) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:283) - locked <0x00000007d7da8070> (a java.util.HashMap) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:267) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:263) at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:777) - locked <0x00000007d7da8070> (a java.util.HashMap) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:737) at groovy.lang.GroovyClassLoader$InnerLoader.loadClass(GroovyClassLoader.java:449) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:793) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:190) at test.C2.class$(test.C2) at test.C2.$get$$class$test$C4(test.C2) at test.C2.<init>(test.C2:7) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at Groovy4736$3.run(Groovy4736.java:169) "Compiling and instantiation 2": at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:776) - waiting to lock <0x00000007d7da8070> (a java.util.HashMap) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:737) at groovy.lang.GroovyClassLoader$InnerLoader.loadClass(GroovyClassLoader.java:449) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:793) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:190) at test.D1.class$(test.D1) at test.D1.$get$$class$test$E3(test.D1) at test.D1.<init>(test.D1:4)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at Groovy4736$3.run(Groovy4736.java:169)
More details about this bug are at GROOVY-4736 JIRA page.

How To Reproduce:

This bug is reproduced under groovy 1.7.9 and JDK 1.6.0_33.
Execute the following scripts to run the test to reproduce the bug (assume the location of the groovy test project is groovy_test_home).

Linux:
${groovy_test_home}/scripts/run4736.sh [--threadnum arg] [--monitoroff]
Windows:
%groovy_test_home%\scripts\run4736.bat [--threadnum arg] [--monitoroff]

The default argument values will be taken if not specified.For example,
${groovy_test_home}/scripts/run4736.sh
is the same as
${groovy_test_home}/scripts/run4736.sh --threadnum 3

Option Function Default Value Valid Values
--threadnum, -tn thread number 3 integer
--monitoroff, -mo Turn off to stop reporting bug messages and ending program when the test runs into the expected concurrency bug which is a deadlock.
User has to terminate the program manually when this option is set